

<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="Description" content="scikit-learn: machine learning in Python">

  
  <title>6.2. Feature extraction &mdash; scikit-learn 0.22 documentation</title>
  
  <link rel="canonical" href="http://scikit-learn.org/stable/modules/feature_extraction.html" />

  
  <link rel="shortcut icon" href="../_static/favicon.ico"/>
  

  <link rel="stylesheet" href="../_static/css/vendor/bootstrap.min.css" type="text/css" />
  <link rel="stylesheet" href="../_static/gallery.css" type="text/css" />
  <link rel="stylesheet" href="../_static/css/theme.css" type="text/css" />
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script> 
</head>
<body>
<nav id="navbar" class="sk-docs-navbar navbar navbar-expand-md navbar-light bg-light py-0">
  <div class="container-fluid sk-docs-container px-0">
      <a class="navbar-brand py-0" href="../index.html">
        <img
          class="sk-brand-img"
          src="../_static/scikit-learn-logo-small.png"
          alt="logo"/>
      </a>
    <button
      id="sk-navbar-toggler"
      class="navbar-toggler"
      type="button"
      data-toggle="collapse"
      data-target="#navbarSupportedContent"
      aria-controls="navbarSupportedContent"
      aria-expanded="false"
      aria-label="Toggle navigation"
    >
      <span class="navbar-toggler-icon"></span>
    </button>

    <div class="sk-navbar-collapse collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav mr-auto">
        <li class="nav-item">
          <a class="sk-nav-link nav-link" href="../install.html">Install</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link" href="../user_guide.html">User Guide</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link" href="classes.html">API</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link" href="../auto_examples/index.html">Examples</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../getting_started.html">Getting Started</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../tutorial/index.html">Tutorial</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../glossary.html">Glossary</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../developers/index.html">Development</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../faq.html">FAQ</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../related_projects.html">Related packages</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../roadmap.html">Roadmap</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="../about.html">About us</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="https://github.com/scikit-learn/scikit-learn">GitHub</a>
        </li>
        <li class="nav-item">
          <a class="sk-nav-link nav-link nav-more-item-mobile-items" href="https://scikit-learn.org/dev/versions.html">Other Versions</a>
        </li>
        <li class="nav-item dropdown nav-more-item-dropdown">
          <a class="sk-nav-link nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">More</a>
          <div class="dropdown-menu" aria-labelledby="navbarDropdown">
              <a class="sk-nav-dropdown-item dropdown-item" href="../getting_started.html">Getting Started</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../tutorial/index.html">Tutorial</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../glossary.html">Glossary</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../developers/index.html">Development</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../faq.html">FAQ</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../related_projects.html">Related packages</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../roadmap.html">Roadmap</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="../about.html">About us</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="https://github.com/scikit-learn/scikit-learn">GitHub</a>
              <a class="sk-nav-dropdown-item dropdown-item" href="https://scikit-learn.org/dev/versions.html">Other Versions</a>
          </div>
        </li>
      </ul>
      <div id="searchbox" role="search">
          <div class="searchformwrapper">
          <form class="search" action="../search.html" method="get">
            <input class="sk-search-text-input" type="text" name="q" aria-labelledby="searchlabel" />
            <input class="sk-search-text-btn" type="submit" value="Go" />
          </form>
          </div>
      </div>
    </div>
  </div>
</nav>
<div class="d-flex" id="sk-doc-wrapper">
    <input type="checkbox" name="sk-toggle-checkbox" id="sk-toggle-checkbox">
    <label id="sk-sidemenu-toggle" class="sk-btn-toggle-toc btn sk-btn-primary" for="sk-toggle-checkbox">Toggle Menu</label>
    <div id="sk-sidebar-wrapper" class="border-right">
      <div class="sk-sidebar-toc-wrapper">
        <div class="sk-sidebar-toc-logo">
          <a href="../index.html">
            <img
              class="sk-brand-img"
              src="../_static/scikit-learn-logo-small.png"
              alt="logo"/>
          </a>
        </div>
        <div class="btn-group w-100 mb-2" role="group" aria-label="rellinks">
            <a href="compose.html" role="button" class="btn sk-btn-rellink py-1" sk-rellink-tooltip="6.1. Pipelines and composite estimators">Prev</a><a href="../data_transforms.html" role="button" class="btn sk-btn-rellink py-1" sk-rellink-tooltip="6. Dataset transformations">Up</a>
            <a href="preprocessing.html" role="button" class="btn sk-btn-rellink py-1" sk-rellink-tooltip="6.3. Preprocessing data">Next</a>
        </div>
        <div class="alert alert-danger p-1 mb-2" role="alert">
          <p class="text-center mb-0">
          <strong>scikit-learn 0.22</strong><br/>
          <a href="http://scikit-learn.org/dev/versions.html">Other versions</a>
          </p>
        </div>
        <div class="alert alert-warning p-1 mb-2" role="alert">
          <p class="text-center mb-0">
            Please <a class="font-weight-bold" href="../about.html#citing-scikit-learn"><string>cite us</string></a> if you use the software.
          </p>
        </div>
          <div class="sk-sidebar-toc">
            <ul>
<li><a class="reference internal" href="#">6.2. Feature extraction</a><ul>
<li><a class="reference internal" href="#loading-features-from-dicts">6.2.1. Loading features from dicts</a></li>
<li><a class="reference internal" href="#feature-hashing">6.2.2. Feature hashing</a><ul>
<li><a class="reference internal" href="#implementation-details">6.2.2.1. Implementation details</a></li>
</ul>
</li>
<li><a class="reference internal" href="#text-feature-extraction">6.2.3. Text feature extraction</a><ul>
<li><a class="reference internal" href="#the-bag-of-words-representation">6.2.3.1. The Bag of Words representation</a></li>
<li><a class="reference internal" href="#sparsity">6.2.3.2. Sparsity</a></li>
<li><a class="reference internal" href="#common-vectorizer-usage">6.2.3.3. Common Vectorizer usage</a><ul>
<li><a class="reference internal" href="#using-stop-words">6.2.3.3.1. Using stop words</a></li>
</ul>
</li>
<li><a class="reference internal" href="#tfidf-term-weighting">6.2.3.4. Tf–idf term weighting</a></li>
<li><a class="reference internal" href="#decoding-text-files">6.2.3.5. Decoding text files</a></li>
<li><a class="reference internal" href="#applications-and-examples">6.2.3.6. Applications and examples</a></li>
<li><a class="reference internal" href="#limitations-of-the-bag-of-words-representation">6.2.3.7. Limitations of the Bag of Words representation</a></li>
<li><a class="reference internal" href="#vectorizing-a-large-text-corpus-with-the-hashing-trick">6.2.3.8. Vectorizing a large text corpus with the hashing trick</a></li>
<li><a class="reference internal" href="#performing-out-of-core-scaling-with-hashingvectorizer">6.2.3.9. Performing out-of-core scaling with HashingVectorizer</a></li>
<li><a class="reference internal" href="#customizing-the-vectorizer-classes">6.2.3.10. Customizing the vectorizer classes</a></li>
</ul>
</li>
<li><a class="reference internal" href="#image-feature-extraction">6.2.4. Image feature extraction</a><ul>
<li><a class="reference internal" href="#patch-extraction">6.2.4.1. Patch extraction</a></li>
<li><a class="reference internal" href="#connectivity-graph-of-an-image">6.2.4.2. Connectivity graph of an image</a></li>
</ul>
</li>
</ul>
</li>
</ul>

          </div>
      </div>
    </div>
    <div id="sk-page-content-wrapper">
      <div class="sk-page-content container-fluid body px-md-3" role="main">
        
  <div class="section" id="feature-extraction">
<span id="id1"></span><h1>6.2. Feature extraction<a class="headerlink" href="#feature-extraction" title="Permalink to this headline">¶</a></h1>
<p>The <a class="reference internal" href="classes.html#module-sklearn.feature_extraction" title="sklearn.feature_extraction"><code class="xref py py-mod docutils literal notranslate"><span class="pre">sklearn.feature_extraction</span></code></a> module can be used to extract
features in a format supported by machine learning algorithms from datasets
consisting of formats such as text and image.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Feature extraction is very different from <a class="reference internal" href="feature_selection.html#feature-selection"><span class="std std-ref">Feature selection</span></a>:
the former consists in transforming arbitrary data, such as text or
images, into numerical features usable for machine learning. The latter
is a machine learning technique applied on these features.</p>
</div>
<div class="section" id="loading-features-from-dicts">
<span id="dict-feature-extraction"></span><h2>6.2.1. Loading features from dicts<a class="headerlink" href="#loading-features-from-dicts" title="Permalink to this headline">¶</a></h2>
<p>The class <a class="reference internal" href="generated/sklearn.feature_extraction.DictVectorizer.html#sklearn.feature_extraction.DictVectorizer" title="sklearn.feature_extraction.DictVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">DictVectorizer</span></code></a> can be used to convert feature
arrays represented as lists of standard Python <code class="docutils literal notranslate"><span class="pre">dict</span></code> objects to the
NumPy/SciPy representation used by scikit-learn estimators.</p>
<p>While not particularly fast to process, Python’s <code class="docutils literal notranslate"><span class="pre">dict</span></code> has the
advantages of being convenient to use, being sparse (absent features
need not be stored) and storing feature names in addition to values.</p>
<p><a class="reference internal" href="generated/sklearn.feature_extraction.DictVectorizer.html#sklearn.feature_extraction.DictVectorizer" title="sklearn.feature_extraction.DictVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">DictVectorizer</span></code></a> implements what is called one-of-K or “one-hot”
coding for categorical (aka nominal, discrete) features. Categorical
features are “attribute-value” pairs where the value is restricted
to a list of discrete of possibilities without ordering (e.g. topic
identifiers, types of objects, tags, names…).</p>
<p>In the following, “city” is a categorical attribute while “temperature”
is a traditional numerical feature:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">measurements</span> <span class="o">=</span> <span class="p">[</span>
<span class="gp">... </span>    <span class="p">{</span><span class="s1">&#39;city&#39;</span><span class="p">:</span> <span class="s1">&#39;Dubai&#39;</span><span class="p">,</span> <span class="s1">&#39;temperature&#39;</span><span class="p">:</span> <span class="mf">33.</span><span class="p">},</span>
<span class="gp">... </span>    <span class="p">{</span><span class="s1">&#39;city&#39;</span><span class="p">:</span> <span class="s1">&#39;London&#39;</span><span class="p">,</span> <span class="s1">&#39;temperature&#39;</span><span class="p">:</span> <span class="mf">12.</span><span class="p">},</span>
<span class="gp">... </span>    <span class="p">{</span><span class="s1">&#39;city&#39;</span><span class="p">:</span> <span class="s1">&#39;San Francisco&#39;</span><span class="p">,</span> <span class="s1">&#39;temperature&#39;</span><span class="p">:</span> <span class="mf">18.</span><span class="p">},</span>
<span class="gp">... </span><span class="p">]</span>

<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">sklearn.feature_extraction</span> <span class="kn">import</span> <span class="n">DictVectorizer</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">vec</span> <span class="o">=</span> <span class="n">DictVectorizer</span><span class="p">()</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">vec</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">measurements</span><span class="p">)</span><span class="o">.</span><span class="n">toarray</span><span class="p">()</span>
<span class="go">array([[ 1.,  0.,  0., 33.],</span>
<span class="go">       [ 0.,  1.,  0., 12.],</span>
<span class="go">       [ 0.,  0.,  1., 18.]])</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">vec</span><span class="o">.</span><span class="n">get_feature_names</span><span class="p">()</span>
<span class="go">[&#39;city=Dubai&#39;, &#39;city=London&#39;, &#39;city=San Francisco&#39;, &#39;temperature&#39;]</span>
</pre></div>
</div>
<p><a class="reference internal" href="generated/sklearn.feature_extraction.DictVectorizer.html#sklearn.feature_extraction.DictVectorizer" title="sklearn.feature_extraction.DictVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">DictVectorizer</span></code></a> is also a useful representation transformation
for training sequence classifiers in Natural Language Processing models
that typically work by extracting feature windows around a particular
word of interest.</p>
<p>For example, suppose that we have a first algorithm that extracts Part of
Speech (PoS) tags that we want to use as complementary tags for training
a sequence classifier (e.g. a chunker). The following dict could be
such a window of features extracted around the word ‘sat’ in the sentence
‘The cat sat on the mat.’:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">pos_window</span> <span class="o">=</span> <span class="p">[</span>
<span class="gp">... </span>    <span class="p">{</span>
<span class="gp">... </span>        <span class="s1">&#39;word-2&#39;</span><span class="p">:</span> <span class="s1">&#39;the&#39;</span><span class="p">,</span>
<span class="gp">... </span>        <span class="s1">&#39;pos-2&#39;</span><span class="p">:</span> <span class="s1">&#39;DT&#39;</span><span class="p">,</span>
<span class="gp">... </span>        <span class="s1">&#39;word-1&#39;</span><span class="p">:</span> <span class="s1">&#39;cat&#39;</span><span class="p">,</span>
<span class="gp">... </span>        <span class="s1">&#39;pos-1&#39;</span><span class="p">:</span> <span class="s1">&#39;NN&#39;</span><span class="p">,</span>
<span class="gp">... </span>        <span class="s1">&#39;word+1&#39;</span><span class="p">:</span> <span class="s1">&#39;on&#39;</span><span class="p">,</span>
<span class="gp">... </span>        <span class="s1">&#39;pos+1&#39;</span><span class="p">:</span> <span class="s1">&#39;PP&#39;</span><span class="p">,</span>
<span class="gp">... </span>    <span class="p">},</span>
<span class="gp">... </span>    <span class="c1"># in a real application one would extract many such dictionaries</span>
<span class="gp">... </span><span class="p">]</span>
</pre></div>
</div>
<p>This description can be vectorized into a sparse two-dimensional matrix
suitable for feeding into a classifier (maybe after being piped into a
<a class="reference internal" href="generated/sklearn.feature_extraction.text.TfidfTransformer.html#sklearn.feature_extraction.text.TfidfTransformer" title="sklearn.feature_extraction.text.TfidfTransformer"><code class="xref py py-class docutils literal notranslate"><span class="pre">text.TfidfTransformer</span></code></a> for normalization):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">vec</span> <span class="o">=</span> <span class="n">DictVectorizer</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">pos_vectorized</span> <span class="o">=</span> <span class="n">vec</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">pos_window</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">pos_vectorized</span>
<span class="go">&lt;1x6 sparse matrix of type &#39;&lt;... &#39;numpy.float64&#39;&gt;&#39;</span>
<span class="go">    with 6 stored elements in Compressed Sparse ... format&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">pos_vectorized</span><span class="o">.</span><span class="n">toarray</span><span class="p">()</span>
<span class="go">array([[1., 1., 1., 1., 1., 1.]])</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">vec</span><span class="o">.</span><span class="n">get_feature_names</span><span class="p">()</span>
<span class="go">[&#39;pos+1=PP&#39;, &#39;pos-1=NN&#39;, &#39;pos-2=DT&#39;, &#39;word+1=on&#39;, &#39;word-1=cat&#39;, &#39;word-2=the&#39;]</span>
</pre></div>
</div>
<p>As you can imagine, if one extracts such a context around each individual
word of a corpus of documents the resulting matrix will be very wide
(many one-hot-features) with most of them being valued to zero most
of the time. So as to make the resulting data structure able to fit in
memory the <code class="docutils literal notranslate"><span class="pre">DictVectorizer</span></code> class uses a <code class="docutils literal notranslate"><span class="pre">scipy.sparse</span></code> matrix by
default instead of a <code class="docutils literal notranslate"><span class="pre">numpy.ndarray</span></code>.</p>
</div>
<div class="section" id="feature-hashing">
<span id="id2"></span><h2>6.2.2. Feature hashing<a class="headerlink" href="#feature-hashing" title="Permalink to this headline">¶</a></h2>
<p>The class <a class="reference internal" href="generated/sklearn.feature_extraction.FeatureHasher.html#sklearn.feature_extraction.FeatureHasher" title="sklearn.feature_extraction.FeatureHasher"><code class="xref py py-class docutils literal notranslate"><span class="pre">FeatureHasher</span></code></a> is a high-speed, low-memory vectorizer that
uses a technique known as
<a class="reference external" href="https://en.wikipedia.org/wiki/Feature_hashing">feature hashing</a>,
or the “hashing trick”.
Instead of building a hash table of the features encountered in training,
as the vectorizers do, instances of <a class="reference internal" href="generated/sklearn.feature_extraction.FeatureHasher.html#sklearn.feature_extraction.FeatureHasher" title="sklearn.feature_extraction.FeatureHasher"><code class="xref py py-class docutils literal notranslate"><span class="pre">FeatureHasher</span></code></a>
apply a hash function to the features
to determine their column index in sample matrices directly.
The result is increased speed and reduced memory usage,
at the expense of inspectability;
the hasher does not remember what the input features looked like
and has no <code class="docutils literal notranslate"><span class="pre">inverse_transform</span></code> method.</p>
<p>Since the hash function might cause collisions between (unrelated) features,
a signed hash function is used and the sign of the hash value
determines the sign of the value stored in the output matrix for a feature.
This way, collisions are likely to cancel out rather than accumulate error,
and the expected mean of any output feature’s value is zero. This mechanism
is enabled by default with <code class="docutils literal notranslate"><span class="pre">alternate_sign=True</span></code> and is particularly useful
for small hash table sizes (<code class="docutils literal notranslate"><span class="pre">n_features</span> <span class="pre">&lt;</span> <span class="pre">10000</span></code>). For large hash table
sizes, it can be disabled, to allow the output to be passed to estimators like
<a class="reference internal" href="generated/sklearn.naive_bayes.MultinomialNB.html#sklearn.naive_bayes.MultinomialNB" title="sklearn.naive_bayes.MultinomialNB"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.naive_bayes.MultinomialNB</span></code></a> or
<a class="reference internal" href="generated/sklearn.feature_selection.chi2.html#sklearn.feature_selection.chi2" title="sklearn.feature_selection.chi2"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.feature_selection.chi2</span></code></a>
feature selectors that expect non-negative inputs.</p>
<p><a class="reference internal" href="generated/sklearn.feature_extraction.FeatureHasher.html#sklearn.feature_extraction.FeatureHasher" title="sklearn.feature_extraction.FeatureHasher"><code class="xref py py-class docutils literal notranslate"><span class="pre">FeatureHasher</span></code></a> accepts either mappings
(like Python’s <code class="docutils literal notranslate"><span class="pre">dict</span></code> and its variants in the <code class="docutils literal notranslate"><span class="pre">collections</span></code> module),
<code class="docutils literal notranslate"><span class="pre">(feature,</span> <span class="pre">value)</span></code> pairs, or strings,
depending on the constructor parameter <code class="docutils literal notranslate"><span class="pre">input_type</span></code>.
Mapping are treated as lists of <code class="docutils literal notranslate"><span class="pre">(feature,</span> <span class="pre">value)</span></code> pairs,
while single strings have an implicit value of 1,
so <code class="docutils literal notranslate"><span class="pre">['feat1',</span> <span class="pre">'feat2',</span> <span class="pre">'feat3']</span></code> is interpreted as
<code class="docutils literal notranslate"><span class="pre">[('feat1',</span> <span class="pre">1),</span> <span class="pre">('feat2',</span> <span class="pre">1),</span> <span class="pre">('feat3',</span> <span class="pre">1)]</span></code>.
If a single feature occurs multiple times in a sample,
the associated values will be summed
(so <code class="docutils literal notranslate"><span class="pre">('feat',</span> <span class="pre">2)</span></code> and <code class="docutils literal notranslate"><span class="pre">('feat',</span> <span class="pre">3.5)</span></code> become <code class="docutils literal notranslate"><span class="pre">('feat',</span> <span class="pre">5.5)</span></code>).
The output from <a class="reference internal" href="generated/sklearn.feature_extraction.FeatureHasher.html#sklearn.feature_extraction.FeatureHasher" title="sklearn.feature_extraction.FeatureHasher"><code class="xref py py-class docutils literal notranslate"><span class="pre">FeatureHasher</span></code></a> is always a <code class="docutils literal notranslate"><span class="pre">scipy.sparse</span></code> matrix
in the CSR format.</p>
<p>Feature hashing can be employed in document classification,
but unlike <a class="reference internal" href="generated/sklearn.feature_extraction.text.CountVectorizer.html#sklearn.feature_extraction.text.CountVectorizer" title="sklearn.feature_extraction.text.CountVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">text.CountVectorizer</span></code></a>,
<a class="reference internal" href="generated/sklearn.feature_extraction.FeatureHasher.html#sklearn.feature_extraction.FeatureHasher" title="sklearn.feature_extraction.FeatureHasher"><code class="xref py py-class docutils literal notranslate"><span class="pre">FeatureHasher</span></code></a> does not do word
splitting or any other preprocessing except Unicode-to-UTF-8 encoding;
see <a class="reference internal" href="#hashing-vectorizer"><span class="std std-ref">Vectorizing a large text corpus with the hashing trick</span></a>, below, for a combined tokenizer/hasher.</p>
<p>As an example, consider a word-level natural language processing task
that needs features extracted from <code class="docutils literal notranslate"><span class="pre">(token,</span> <span class="pre">part_of_speech)</span></code> pairs.
One could use a Python generator function to extract features:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">token_features</span><span class="p">(</span><span class="n">token</span><span class="p">,</span> <span class="n">part_of_speech</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">token</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</span>
        <span class="k">yield</span> <span class="s2">&quot;numeric&quot;</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">yield</span> <span class="s2">&quot;token=</span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">token</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span>
        <span class="k">yield</span> <span class="s2">&quot;token,pos=</span><span class="si">{}</span><span class="s2">,</span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">token</span><span class="p">,</span> <span class="n">part_of_speech</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">isupper</span><span class="p">():</span>
        <span class="k">yield</span> <span class="s2">&quot;uppercase_initial&quot;</span>
    <span class="k">if</span> <span class="n">token</span><span class="o">.</span><span class="n">isupper</span><span class="p">():</span>
        <span class="k">yield</span> <span class="s2">&quot;all_uppercase&quot;</span>
    <span class="k">yield</span> <span class="s2">&quot;pos=</span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">part_of_speech</span><span class="p">)</span>
</pre></div>
</div>
<p>Then, the <code class="docutils literal notranslate"><span class="pre">raw_X</span></code> to be fed to <code class="docutils literal notranslate"><span class="pre">FeatureHasher.transform</span></code>
can be constructed using:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">raw_X</span> <span class="o">=</span> <span class="p">(</span><span class="n">token_features</span><span class="p">(</span><span class="n">tok</span><span class="p">,</span> <span class="n">pos_tagger</span><span class="p">(</span><span class="n">tok</span><span class="p">))</span> <span class="k">for</span> <span class="n">tok</span> <span class="ow">in</span> <span class="n">corpus</span><span class="p">)</span>
</pre></div>
</div>
<p>and fed to a hasher with:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">hasher</span> <span class="o">=</span> <span class="n">FeatureHasher</span><span class="p">(</span><span class="n">input_type</span><span class="o">=</span><span class="s1">&#39;string&#39;</span><span class="p">)</span>
<span class="n">X</span> <span class="o">=</span> <span class="n">hasher</span><span class="o">.</span><span class="n">transform</span><span class="p">(</span><span class="n">raw_X</span><span class="p">)</span>
</pre></div>
</div>
<p>to get a <code class="docutils literal notranslate"><span class="pre">scipy.sparse</span></code> matrix <code class="docutils literal notranslate"><span class="pre">X</span></code>.</p>
<p>Note the use of a generator comprehension,
which introduces laziness into the feature extraction:
tokens are only processed on demand from the hasher.</p>
<div class="section" id="implementation-details">
<h3>6.2.2.1. Implementation details<a class="headerlink" href="#implementation-details" title="Permalink to this headline">¶</a></h3>
<p><a class="reference internal" href="generated/sklearn.feature_extraction.FeatureHasher.html#sklearn.feature_extraction.FeatureHasher" title="sklearn.feature_extraction.FeatureHasher"><code class="xref py py-class docutils literal notranslate"><span class="pre">FeatureHasher</span></code></a> uses the signed 32-bit variant of MurmurHash3.
As a result (and because of limitations in <code class="docutils literal notranslate"><span class="pre">scipy.sparse</span></code>),
the maximum number of features supported is currently <span class="math notranslate nohighlight">\(2^{31} - 1\)</span>.</p>
<p>The original formulation of the hashing trick by Weinberger et al.
used two separate hash functions <span class="math notranslate nohighlight">\(h\)</span> and <span class="math notranslate nohighlight">\(\xi\)</span>
to determine the column index and sign of a feature, respectively.
The present implementation works under the assumption
that the sign bit of MurmurHash3 is independent of its other bits.</p>
<p>Since a simple modulo is used to transform the hash function to a column index,
it is advisable to use a power of two as the <code class="docutils literal notranslate"><span class="pre">n_features</span></code> parameter;
otherwise the features will not be mapped evenly to the columns.</p>
<div class="topic">
<p class="topic-title">References:</p>
<ul class="simple">
<li><p>Kilian Weinberger, Anirban Dasgupta, John Langford, Alex Smola and
Josh Attenberg (2009). <a class="reference external" href="https://alex.smola.org/papers/2009/Weinbergeretal09.pdf">Feature hashing for large scale multitask learning</a>. Proc. ICML.</p></li>
<li><p><a class="reference external" href="https://github.com/aappleby/smhasher">MurmurHash3</a>.</p></li>
</ul>
</div>
</div>
</div>
<div class="section" id="text-feature-extraction">
<span id="id4"></span><h2>6.2.3. Text feature extraction<a class="headerlink" href="#text-feature-extraction" title="Permalink to this headline">¶</a></h2>
<div class="section" id="the-bag-of-words-representation">
<h3>6.2.3.1. The Bag of Words representation<a class="headerlink" href="#the-bag-of-words-representation" title="Permalink to this headline">¶</a></h3>
<p>Text Analysis is a major application field for machine learning
algorithms. However the raw data, a sequence of symbols cannot be fed
directly to the algorithms themselves as most of them expect numerical
feature vectors with a fixed size rather than the raw text documents
with variable length.</p>
<p>In order to address this, scikit-learn provides utilities for the most
common ways to extract numerical features from text content, namely:</p>
<ul class="simple">
<li><p><strong>tokenizing</strong> strings and giving an integer id for each possible token,
for instance by using white-spaces and punctuation as token separators.</p></li>
<li><p><strong>counting</strong> the occurrences of tokens in each document.</p></li>
<li><p><strong>normalizing</strong> and weighting with diminishing importance tokens that
occur in the majority of samples / documents.</p></li>
</ul>
<p>In this scheme, features and samples are defined as follows:</p>
<ul class="simple">
<li><p>each <strong>individual token occurrence frequency</strong> (normalized or not)
is treated as a <strong>feature</strong>.</p></li>
<li><p>the vector of all the token frequencies for a given <strong>document</strong> is
considered a multivariate <strong>sample</strong>.</p></li>
</ul>
<p>A corpus of documents can thus be represented by a matrix with one row
per document and one column per token (e.g. word) occurring in the corpus.</p>
<p>We call <strong>vectorization</strong> the general process of turning a collection
of text documents into numerical feature vectors. This specific strategy
(tokenization, counting and normalization) is called the <strong>Bag of Words</strong>
or “Bag of n-grams” representation. Documents are described by word
occurrences while completely ignoring the relative position information
of the words in the document.</p>
</div>
<div class="section" id="sparsity">
<h3>6.2.3.2. Sparsity<a class="headerlink" href="#sparsity" title="Permalink to this headline">¶</a></h3>
<p>As most documents will typically use a very small subset of the words used in
the corpus, the resulting matrix will have many feature values that are
zeros (typically more than 99% of them).</p>
<p>For instance a collection of 10,000 short text documents (such as emails)
will use a vocabulary with a size in the order of 100,000 unique words in
total while each document will use 100 to 1000 unique words individually.</p>
<p>In order to be able to store such a matrix in memory but also to speed
up algebraic operations matrix / vector, implementations will typically
use a sparse representation such as the implementations available in the
<code class="docutils literal notranslate"><span class="pre">scipy.sparse</span></code> package.</p>
</div>
<div class="section" id="common-vectorizer-usage">
<h3>6.2.3.3. Common Vectorizer usage<a class="headerlink" href="#common-vectorizer-usage" title="Permalink to this headline">¶</a></h3>
<p><a class="reference internal" href="generated/sklearn.feature_extraction.text.CountVectorizer.html#sklearn.feature_extraction.text.CountVectorizer" title="sklearn.feature_extraction.text.CountVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">CountVectorizer</span></code></a> implements both tokenization and occurrence
counting in a single class:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">sklearn.feature_extraction.text</span> <span class="kn">import</span> <span class="n">CountVectorizer</span>
</pre></div>
</div>
<p>This model has many parameters, however the default values are quite
reasonable (please see  the <a class="reference internal" href="classes.html#text-feature-extraction-ref"><span class="std std-ref">reference documentation</span></a> for the details):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">vectorizer</span> <span class="o">=</span> <span class="n">CountVectorizer</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">vectorizer</span>
<span class="go">CountVectorizer()</span>
</pre></div>
</div>
<p>Let’s use it to tokenize and count the word occurrences of a minimalistic
corpus of text documents:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">corpus</span> <span class="o">=</span> <span class="p">[</span>
<span class="gp">... </span>    <span class="s1">&#39;This is the first document.&#39;</span><span class="p">,</span>
<span class="gp">... </span>    <span class="s1">&#39;This is the second second document.&#39;</span><span class="p">,</span>
<span class="gp">... </span>    <span class="s1">&#39;And the third one.&#39;</span><span class="p">,</span>
<span class="gp">... </span>    <span class="s1">&#39;Is this the first document?&#39;</span><span class="p">,</span>
<span class="gp">... </span><span class="p">]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">X</span> <span class="o">=</span> <span class="n">vectorizer</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">corpus</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">X</span>
<span class="go">&lt;4x9 sparse matrix of type &#39;&lt;... &#39;numpy.int64&#39;&gt;&#39;</span>
<span class="go">    with 19 stored elements in Compressed Sparse ... format&gt;</span>
</pre></div>
</div>
<p>The default configuration tokenizes the string by extracting words of
at least 2 letters. The specific function that does this step can be
requested explicitly:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">analyze</span> <span class="o">=</span> <span class="n">vectorizer</span><span class="o">.</span><span class="n">build_analyzer</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">analyze</span><span class="p">(</span><span class="s2">&quot;This is a text document to analyze.&quot;</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span>
<span class="gp">... </span>    <span class="p">[</span><span class="s1">&#39;this&#39;</span><span class="p">,</span> <span class="s1">&#39;is&#39;</span><span class="p">,</span> <span class="s1">&#39;text&#39;</span><span class="p">,</span> <span class="s1">&#39;document&#39;</span><span class="p">,</span> <span class="s1">&#39;to&#39;</span><span class="p">,</span> <span class="s1">&#39;analyze&#39;</span><span class="p">])</span>
<span class="go">True</span>
</pre></div>
</div>
<p>Each term found by the analyzer during the fit is assigned a unique
integer index corresponding to a column in the resulting matrix. This
interpretation of the columns can be retrieved as follows:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">vectorizer</span><span class="o">.</span><span class="n">get_feature_names</span><span class="p">()</span> <span class="o">==</span> <span class="p">(</span>
<span class="gp">... </span>    <span class="p">[</span><span class="s1">&#39;and&#39;</span><span class="p">,</span> <span class="s1">&#39;document&#39;</span><span class="p">,</span> <span class="s1">&#39;first&#39;</span><span class="p">,</span> <span class="s1">&#39;is&#39;</span><span class="p">,</span> <span class="s1">&#39;one&#39;</span><span class="p">,</span>
<span class="gp">... </span>     <span class="s1">&#39;second&#39;</span><span class="p">,</span> <span class="s1">&#39;the&#39;</span><span class="p">,</span> <span class="s1">&#39;third&#39;</span><span class="p">,</span> <span class="s1">&#39;this&#39;</span><span class="p">])</span>
<span class="go">True</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">X</span><span class="o">.</span><span class="n">toarray</span><span class="p">()</span>
<span class="go">array([[0, 1, 1, 1, 0, 0, 1, 0, 1],</span>
<span class="go">       [0, 1, 0, 1, 0, 2, 1, 0, 1],</span>
<span class="go">       [1, 0, 0, 0, 1, 0, 1, 1, 0],</span>
<span class="go">       [0, 1, 1, 1, 0, 0, 1, 0, 1]]...)</span>
</pre></div>
</div>
<p>The converse mapping from feature name to column index is stored in the
<code class="docutils literal notranslate"><span class="pre">vocabulary_</span></code> attribute of the vectorizer:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">vectorizer</span><span class="o">.</span><span class="n">vocabulary_</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;document&#39;</span><span class="p">)</span>
<span class="go">1</span>
</pre></div>
</div>
<p>Hence words that were not seen in the training corpus will be completely
ignored in future calls to the transform method:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">vectorizer</span><span class="o">.</span><span class="n">transform</span><span class="p">([</span><span class="s1">&#39;Something completely new.&#39;</span><span class="p">])</span><span class="o">.</span><span class="n">toarray</span><span class="p">()</span>
<span class="go">array([[0, 0, 0, 0, 0, 0, 0, 0, 0]]...)</span>
</pre></div>
</div>
<p>Note that in the previous corpus, the first and the last documents have
exactly the same words hence are encoded in equal vectors. In particular
we lose the information that the last document is an interrogative form. To
preserve some of the local ordering information we can extract 2-grams
of words in addition to the 1-grams (individual words):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">bigram_vectorizer</span> <span class="o">=</span> <span class="n">CountVectorizer</span><span class="p">(</span><span class="n">ngram_range</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span>
<span class="gp">... </span>                                    <span class="n">token_pattern</span><span class="o">=</span><span class="sa">r</span><span class="s1">&#39;\b\w+\b&#39;</span><span class="p">,</span> <span class="n">min_df</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">analyze</span> <span class="o">=</span> <span class="n">bigram_vectorizer</span><span class="o">.</span><span class="n">build_analyzer</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">analyze</span><span class="p">(</span><span class="s1">&#39;Bi-grams are cool!&#39;</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span>
<span class="gp">... </span>    <span class="p">[</span><span class="s1">&#39;bi&#39;</span><span class="p">,</span> <span class="s1">&#39;grams&#39;</span><span class="p">,</span> <span class="s1">&#39;are&#39;</span><span class="p">,</span> <span class="s1">&#39;cool&#39;</span><span class="p">,</span> <span class="s1">&#39;bi grams&#39;</span><span class="p">,</span> <span class="s1">&#39;grams are&#39;</span><span class="p">,</span> <span class="s1">&#39;are cool&#39;</span><span class="p">])</span>
<span class="go">True</span>
</pre></div>
</div>
<p>The vocabulary extracted by this vectorizer is hence much bigger and
can now resolve ambiguities encoded in local positioning patterns:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">X_2</span> <span class="o">=</span> <span class="n">bigram_vectorizer</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">corpus</span><span class="p">)</span><span class="o">.</span><span class="n">toarray</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">X_2</span>
<span class="go">array([[0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0],</span>
<span class="go">       [0, 0, 1, 0, 0, 1, 1, 0, 0, 2, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0],</span>
<span class="go">       [1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0],</span>
<span class="go">       [0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1]]...)</span>
</pre></div>
</div>
<p>In particular the interrogative form “Is this” is only present in the
last document:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">feature_index</span> <span class="o">=</span> <span class="n">bigram_vectorizer</span><span class="o">.</span><span class="n">vocabulary_</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;is this&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">X_2</span><span class="p">[:,</span> <span class="n">feature_index</span><span class="p">]</span>
<span class="go">array([0, 0, 0, 1]...)</span>
</pre></div>
</div>
<div class="section" id="using-stop-words">
<span id="stop-words"></span><h4>6.2.3.3.1. Using stop words<a class="headerlink" href="#using-stop-words" title="Permalink to this headline">¶</a></h4>
<p>Stop words are words like “and”, “the”, “him”, which are presumed to be
uninformative in representing the content of a text, and which may be
removed to avoid them being construed as signal for prediction.  Sometimes,
however, similar words are useful for prediction, such as in classifying
writing style or personality.</p>
<p>There are several known issues in our provided ‘english’ stop word list. It
does not aim to be a general, ‘one-size-fits-all’ solution as some tasks
may require a more custom solution. See <a class="reference internal" href="#nqy18" id="id5"><span>[NQY18]</span></a> for more details.</p>
<p>Please take care in choosing a stop word list.
Popular stop word lists may include words that are highly informative to
some tasks, such as <em>computer</em>.</p>
<p>You should also make sure that the stop word list has had the same
preprocessing and tokenization applied as the one used in the vectorizer.
The word <em>we’ve</em> is split into <em>we</em> and <em>ve</em> by CountVectorizer’s default
tokenizer, so if <em>we’ve</em> is in <code class="docutils literal notranslate"><span class="pre">stop_words</span></code>, but <em>ve</em> is not, <em>ve</em> will
be retained from <em>we’ve</em> in transformed text.  Our vectorizers will try to
identify and warn about some kinds of inconsistencies.</p>
<div class="topic">
<p class="topic-title">References</p>
<dl class="citation">
<dt class="label" id="nqy18"><span class="brackets"><a class="fn-backref" href="#id5">NQY18</a></span></dt>
<dd><p>J. Nothman, H. Qin and R. Yurchak (2018).
<a class="reference external" href="https://aclweb.org/anthology/W18-2502">“Stop Word Lists in Free Open-source Software Packages”</a>.
In <em>Proc. Workshop for NLP Open Source Software</em>.</p>
</dd>
</dl>
</div>
</div>
</div>
<div class="section" id="tfidf-term-weighting">
<span id="tfidf"></span><h3>6.2.3.4. Tf–idf term weighting<a class="headerlink" href="#tfidf-term-weighting" title="Permalink to this headline">¶</a></h3>
<p>In a large text corpus, some words will be very present (e.g. “the”, “a”,
“is” in English) hence carrying very little meaningful information about
the actual contents of the document. If we were to feed the direct count
data directly to a classifier those very frequent terms would shadow
the frequencies of rarer yet more interesting terms.</p>
<p>In order to re-weight the count features into floating point values
suitable for usage by a classifier it is very common to use the tf–idf
transform.</p>
<p>Tf means <strong>term-frequency</strong> while tf–idf means term-frequency times
<strong>inverse document-frequency</strong>:
<span class="math notranslate nohighlight">\(\text{tf-idf(t,d)}=\text{tf(t,d)} \times \text{idf(t)}\)</span>.</p>
<p>Using the <code class="docutils literal notranslate"><span class="pre">TfidfTransformer</span></code>’s default settings,
<code class="docutils literal notranslate"><span class="pre">TfidfTransformer(norm='l2',</span> <span class="pre">use_idf=True,</span> <span class="pre">smooth_idf=True,</span> <span class="pre">sublinear_tf=False)</span></code>
the term frequency, the number of times a term occurs in a given document,
is multiplied with idf component, which is computed as</p>
<p><span class="math notranslate nohighlight">\(\text{idf}(t) = \log{\frac{1 + n}{1+\text{df}(t)}} + 1\)</span>,</p>
<p>where <span class="math notranslate nohighlight">\(n\)</span> is the total number of documents in the document set, and
<span class="math notranslate nohighlight">\(\text{df}(t)\)</span> is the number of documents in the document set that
contain term <span class="math notranslate nohighlight">\(t\)</span>. The resulting tf-idf vectors are then normalized by the
Euclidean norm:</p>
<p><span class="math notranslate nohighlight">\(v_{norm} = \frac{v}{||v||_2} = \frac{v}{\sqrt{v{_1}^2 +
v{_2}^2 + \dots + v{_n}^2}}\)</span>.</p>
<p>This was originally a term weighting scheme developed for information retrieval
(as a ranking function for search engines results) that has also found good
use in document classification and clustering.</p>
<p>The following sections contain further explanations and examples that
illustrate how the tf-idfs are computed exactly and how the tf-idfs
computed in scikit-learn’s <a class="reference internal" href="generated/sklearn.feature_extraction.text.TfidfTransformer.html#sklearn.feature_extraction.text.TfidfTransformer" title="sklearn.feature_extraction.text.TfidfTransformer"><code class="xref py py-class docutils literal notranslate"><span class="pre">TfidfTransformer</span></code></a>
and <a class="reference internal" href="generated/sklearn.feature_extraction.text.TfidfVectorizer.html#sklearn.feature_extraction.text.TfidfVectorizer" title="sklearn.feature_extraction.text.TfidfVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">TfidfVectorizer</span></code></a> differ slightly from the standard textbook
notation that defines the idf as</p>
<p><span class="math notranslate nohighlight">\(\text{idf}(t) = \log{\frac{n}{1+\text{df}(t)}}.\)</span></p>
<p>In the <a class="reference internal" href="generated/sklearn.feature_extraction.text.TfidfTransformer.html#sklearn.feature_extraction.text.TfidfTransformer" title="sklearn.feature_extraction.text.TfidfTransformer"><code class="xref py py-class docutils literal notranslate"><span class="pre">TfidfTransformer</span></code></a> and <a class="reference internal" href="generated/sklearn.feature_extraction.text.TfidfVectorizer.html#sklearn.feature_extraction.text.TfidfVectorizer" title="sklearn.feature_extraction.text.TfidfVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">TfidfVectorizer</span></code></a>
with <code class="docutils literal notranslate"><span class="pre">smooth_idf=False</span></code>, the
“1” count is added to the idf instead of the idf’s denominator:</p>
<p><span class="math notranslate nohighlight">\(\text{idf}(t) = \log{\frac{n}{\text{df}(t)}} + 1\)</span></p>
<p>This normalization is implemented by the <a class="reference internal" href="generated/sklearn.feature_extraction.text.TfidfTransformer.html#sklearn.feature_extraction.text.TfidfTransformer" title="sklearn.feature_extraction.text.TfidfTransformer"><code class="xref py py-class docutils literal notranslate"><span class="pre">TfidfTransformer</span></code></a>
class:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">sklearn.feature_extraction.text</span> <span class="kn">import</span> <span class="n">TfidfTransformer</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">transformer</span> <span class="o">=</span> <span class="n">TfidfTransformer</span><span class="p">(</span><span class="n">smooth_idf</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">transformer</span>
<span class="go">TfidfTransformer(smooth_idf=False)</span>
</pre></div>
</div>
<p>Again please see the <a class="reference internal" href="classes.html#text-feature-extraction-ref"><span class="std std-ref">reference documentation</span></a> for the details on all the parameters.</p>
<p>Let’s take an example with the following counts. The first term is present
100% of the time hence not very interesting. The two other features only
in less than 50% of the time hence probably more representative of the
content of the documents:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">counts</span> <span class="o">=</span> <span class="p">[[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span>
<span class="gp">... </span>          <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span>
<span class="gp">... </span>          <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span>
<span class="gp">... </span>          <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span>
<span class="gp">... </span>          <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span>
<span class="gp">... </span>          <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">]]</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">tfidf</span> <span class="o">=</span> <span class="n">transformer</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">counts</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">tfidf</span>
<span class="go">&lt;6x3 sparse matrix of type &#39;&lt;... &#39;numpy.float64&#39;&gt;&#39;</span>
<span class="go">    with 9 stored elements in Compressed Sparse ... format&gt;</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">tfidf</span><span class="o">.</span><span class="n">toarray</span><span class="p">()</span>
<span class="go">array([[0.81940995, 0.        , 0.57320793],</span>
<span class="go">       [1.        , 0.        , 0.        ],</span>
<span class="go">       [1.        , 0.        , 0.        ],</span>
<span class="go">       [1.        , 0.        , 0.        ],</span>
<span class="go">       [0.47330339, 0.88089948, 0.        ],</span>
<span class="go">       [0.58149261, 0.        , 0.81355169]])</span>
</pre></div>
</div>
<p>Each row is normalized to have unit Euclidean norm:</p>
<p><span class="math notranslate nohighlight">\(v_{norm} = \frac{v}{||v||_2} = \frac{v}{\sqrt{v{_1}^2 +
v{_2}^2 + \dots + v{_n}^2}}\)</span></p>
<p>For example, we can compute the tf-idf of the first term in the first
document in the <code class="docutils literal notranslate"><span class="pre">counts</span></code> array as follows:</p>
<p><span class="math notranslate nohighlight">\(n = 6\)</span></p>
<p><span class="math notranslate nohighlight">\(\text{df}(t)_{\text{term1}} = 6\)</span></p>
<p><span class="math notranslate nohighlight">\(\text{idf}(t)_{\text{term1}} =
\log \frac{n}{\text{df}(t)} + 1 = \log(1)+1 = 1\)</span></p>
<p><span class="math notranslate nohighlight">\(\text{tf-idf}_{\text{term1}} = \text{tf} \times \text{idf} = 3 \times 1 = 3\)</span></p>
<p>Now, if we repeat this computation for the remaining 2 terms in the document,
we get</p>
<p><span class="math notranslate nohighlight">\(\text{tf-idf}_{\text{term2}} = 0 \times (\log(6/1)+1) = 0\)</span></p>
<p><span class="math notranslate nohighlight">\(\text{tf-idf}_{\text{term3}} = 1 \times (\log(6/2)+1) \approx 2.0986\)</span></p>
<p>and the vector of raw tf-idfs:</p>
<p><span class="math notranslate nohighlight">\(\text{tf-idf}_{\text{raw}} = [3, 0, 2.0986].\)</span></p>
<p>Then, applying the Euclidean (L2) norm, we obtain the following tf-idfs
for document 1:</p>
<p><span class="math notranslate nohighlight">\(\frac{[3, 0, 2.0986]}{\sqrt{\big(3^2 + 0^2 + 2.0986^2\big)}}
= [ 0.819,  0,  0.573].\)</span></p>
<p>Furthermore, the default parameter <code class="docutils literal notranslate"><span class="pre">smooth_idf=True</span></code> adds “1” to the numerator
and  denominator as if an extra document was seen containing every term in the
collection exactly once, which prevents zero divisions:</p>
<p><span class="math notranslate nohighlight">\(\text{idf}(t) = \log{\frac{1 + n}{1+\text{df}(t)}} + 1\)</span></p>
<p>Using this modification, the tf-idf of the third term in document 1 changes to
1.8473:</p>
<p><span class="math notranslate nohighlight">\(\text{tf-idf}_{\text{term3}} = 1 \times \log(7/3)+1 \approx 1.8473\)</span></p>
<p>And the L2-normalized tf-idf changes to</p>
<p><span class="math notranslate nohighlight">\(\frac{[3, 0, 1.8473]}{\sqrt{\big(3^2 + 0^2 + 1.8473^2\big)}}
= [0.8515, 0, 0.5243]\)</span>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">transformer</span> <span class="o">=</span> <span class="n">TfidfTransformer</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">transformer</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">counts</span><span class="p">)</span><span class="o">.</span><span class="n">toarray</span><span class="p">()</span>
<span class="go">array([[0.85151335, 0.        , 0.52433293],</span>
<span class="go">       [1.        , 0.        , 0.        ],</span>
<span class="go">       [1.        , 0.        , 0.        ],</span>
<span class="go">       [1.        , 0.        , 0.        ],</span>
<span class="go">       [0.55422893, 0.83236428, 0.        ],</span>
<span class="go">       [0.63035731, 0.        , 0.77630514]])</span>
</pre></div>
</div>
<p>The weights of each
feature computed by the <code class="docutils literal notranslate"><span class="pre">fit</span></code> method call are stored in a model
attribute:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">transformer</span><span class="o">.</span><span class="n">idf_</span>
<span class="go">array([1. ..., 2.25..., 1.84...])</span>
</pre></div>
</div>
<p>As tf–idf is very often used for text features, there is also another
class called <a class="reference internal" href="generated/sklearn.feature_extraction.text.TfidfVectorizer.html#sklearn.feature_extraction.text.TfidfVectorizer" title="sklearn.feature_extraction.text.TfidfVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">TfidfVectorizer</span></code></a> that combines all the options of
<a class="reference internal" href="generated/sklearn.feature_extraction.text.CountVectorizer.html#sklearn.feature_extraction.text.CountVectorizer" title="sklearn.feature_extraction.text.CountVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">CountVectorizer</span></code></a> and <a class="reference internal" href="generated/sklearn.feature_extraction.text.TfidfTransformer.html#sklearn.feature_extraction.text.TfidfTransformer" title="sklearn.feature_extraction.text.TfidfTransformer"><code class="xref py py-class docutils literal notranslate"><span class="pre">TfidfTransformer</span></code></a> in a single model:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">sklearn.feature_extraction.text</span> <span class="kn">import</span> <span class="n">TfidfVectorizer</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">vectorizer</span> <span class="o">=</span> <span class="n">TfidfVectorizer</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">vectorizer</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">corpus</span><span class="p">)</span>
<span class="go">&lt;4x9 sparse matrix of type &#39;&lt;... &#39;numpy.float64&#39;&gt;&#39;</span>
<span class="go">    with 19 stored elements in Compressed Sparse ... format&gt;</span>
</pre></div>
</div>
<p>While the tf–idf normalization is often very useful, there might
be cases where the binary occurrence markers might offer better
features. This can be achieved by using the <code class="docutils literal notranslate"><span class="pre">binary</span></code> parameter
of <a class="reference internal" href="generated/sklearn.feature_extraction.text.CountVectorizer.html#sklearn.feature_extraction.text.CountVectorizer" title="sklearn.feature_extraction.text.CountVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">CountVectorizer</span></code></a>. In particular, some estimators such as
<a class="reference internal" href="naive_bayes.html#bernoulli-naive-bayes"><span class="std std-ref">Bernoulli Naive Bayes</span></a> explicitly model discrete boolean random
variables. Also, very short texts are likely to have noisy tf–idf values
while the binary occurrence info is more stable.</p>
<p>As usual the best way to adjust the feature extraction parameters
is to use a cross-validated grid search, for instance by pipelining the
feature extractor with a classifier:</p>
<blockquote>
<div><ul class="simple">
<li><p><a class="reference internal" href="../auto_examples/model_selection/grid_search_text_feature_extraction.html#sphx-glr-auto-examples-model-selection-grid-search-text-feature-extraction-py"><span class="std std-ref">Sample pipeline for text feature extraction and evaluation</span></a></p></li>
</ul>
</div></blockquote>
</div>
<div class="section" id="decoding-text-files">
<h3>6.2.3.5. Decoding text files<a class="headerlink" href="#decoding-text-files" title="Permalink to this headline">¶</a></h3>
<p>Text is made of characters, but files are made of bytes. These bytes represent
characters according to some <em>encoding</em>. To work with text files in Python,
their bytes must be <em>decoded</em> to a character set called Unicode.
Common encodings are ASCII, Latin-1 (Western Europe), KOI8-R (Russian)
and the universal encodings UTF-8 and UTF-16. Many others exist.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>An encoding can also be called a ‘character set’,
but this term is less accurate: several encodings can exist
for a single character set.</p>
</div>
<p>The text feature extractors in scikit-learn know how to decode text files,
but only if you tell them what encoding the files are in.
The <a class="reference internal" href="generated/sklearn.feature_extraction.text.CountVectorizer.html#sklearn.feature_extraction.text.CountVectorizer" title="sklearn.feature_extraction.text.CountVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">CountVectorizer</span></code></a> takes an <code class="docutils literal notranslate"><span class="pre">encoding</span></code> parameter for this purpose.
For modern text files, the correct encoding is probably UTF-8,
which is therefore the default (<code class="docutils literal notranslate"><span class="pre">encoding=&quot;utf-8&quot;</span></code>).</p>
<p>If the text you are loading is not actually encoded with UTF-8, however,
you will get a <code class="docutils literal notranslate"><span class="pre">UnicodeDecodeError</span></code>.
The vectorizers can be told to be silent about decoding errors
by setting the <code class="docutils literal notranslate"><span class="pre">decode_error</span></code> parameter to either <code class="docutils literal notranslate"><span class="pre">&quot;ignore&quot;</span></code>
or <code class="docutils literal notranslate"><span class="pre">&quot;replace&quot;</span></code>. See the documentation for the Python function
<code class="docutils literal notranslate"><span class="pre">bytes.decode</span></code> for more details
(type <code class="docutils literal notranslate"><span class="pre">help(bytes.decode)</span></code> at the Python prompt).</p>
<p>If you are having trouble decoding text, here are some things to try:</p>
<ul class="simple">
<li><p>Find out what the actual encoding of the text is. The file might come
with a header or README that tells you the encoding, or there might be some
standard encoding you can assume based on where the text comes from.</p></li>
<li><p>You may be able to find out what kind of encoding it is in general
using the UNIX command <code class="docutils literal notranslate"><span class="pre">file</span></code>. The Python <code class="docutils literal notranslate"><span class="pre">chardet</span></code> module comes with
a script called <code class="docutils literal notranslate"><span class="pre">chardetect.py</span></code> that will guess the specific encoding,
though you cannot rely on its guess being correct.</p></li>
<li><p>You could try UTF-8 and disregard the errors. You can decode byte
strings with <code class="docutils literal notranslate"><span class="pre">bytes.decode(errors='replace')</span></code> to replace all
decoding errors with a meaningless character, or set
<code class="docutils literal notranslate"><span class="pre">decode_error='replace'</span></code> in the vectorizer. This may damage the
usefulness of your features.</p></li>
<li><p>Real text may come from a variety of sources that may have used different
encodings, or even be sloppily decoded in a different encoding than the
one it was encoded with. This is common in text retrieved from the Web.
The Python package <a class="reference external" href="https://github.com/LuminosoInsight/python-ftfy">ftfy</a> can automatically sort out some classes of
decoding errors, so you could try decoding the unknown text as <code class="docutils literal notranslate"><span class="pre">latin-1</span></code>
and then using <code class="docutils literal notranslate"><span class="pre">ftfy</span></code> to fix errors.</p></li>
<li><p>If the text is in a mish-mash of encodings that is simply too hard to sort
out (which is the case for the 20 Newsgroups dataset), you can fall back on
a simple single-byte encoding such as <code class="docutils literal notranslate"><span class="pre">latin-1</span></code>. Some text may display
incorrectly, but at least the same sequence of bytes will always represent
the same feature.</p></li>
</ul>
<p>For example, the following snippet uses <code class="docutils literal notranslate"><span class="pre">chardet</span></code>
(not shipped with scikit-learn, must be installed separately)
to figure out the encoding of three texts.
It then vectorizes the texts and prints the learned vocabulary.
The output is not shown here.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">chardet</span>    <span class="c1"># doctest: +SKIP</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">text1</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&quot;Sei mir gegr</span><span class="se">\xc3\xbc\xc3\x9f</span><span class="s2">t mein Sauerkraut&quot;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">text2</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&quot;holdselig sind deine Ger</span><span class="se">\xfc</span><span class="s2">che&quot;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">text3</span> <span class="o">=</span> <span class="sa">b</span><span class="s2">&quot;</span><span class="se">\xff\xfe</span><span class="s2">A</span><span class="se">\x00</span><span class="s2">u</span><span class="se">\x00</span><span class="s2">f</span><span class="se">\x00</span><span class="s2"> </span><span class="se">\x00</span><span class="s2">F</span><span class="se">\x00</span><span class="s2">l</span><span class="se">\x00\xfc\x00</span><span class="s2">g</span><span class="se">\x00</span><span class="s2">e</span><span class="se">\x00</span><span class="s2">l</span><span class="se">\x00</span><span class="s2">n</span><span class="se">\x00</span><span class="s2"> </span><span class="se">\x00</span><span class="s2">d</span><span class="se">\x00</span><span class="s2">e</span><span class="se">\x00</span><span class="s2">s</span><span class="se">\x00</span><span class="s2"> </span><span class="se">\x00</span><span class="s2">G</span><span class="se">\x00</span><span class="s2">e</span><span class="se">\x00</span><span class="s2">s</span><span class="se">\x00</span><span class="s2">a</span><span class="se">\x00</span><span class="s2">n</span><span class="se">\x00</span><span class="s2">g</span><span class="se">\x00</span><span class="s2">e</span><span class="se">\x00</span><span class="s2">s</span><span class="se">\x00</span><span class="s2">,</span><span class="se">\x00</span><span class="s2"> </span><span class="se">\x00</span><span class="s2">H</span><span class="se">\x00</span><span class="s2">e</span><span class="se">\x00</span><span class="s2">r</span><span class="se">\x00</span><span class="s2">z</span><span class="se">\x00</span><span class="s2">l</span><span class="se">\x00</span><span class="s2">i</span><span class="se">\x00</span><span class="s2">e</span><span class="se">\x00</span><span class="s2">b</span><span class="se">\x00</span><span class="s2">c</span><span class="se">\x00</span><span class="s2">h</span><span class="se">\x00</span><span class="s2">e</span><span class="se">\x00</span><span class="s2">n</span><span class="se">\x00</span><span class="s2">,</span><span class="se">\x00</span><span class="s2"> </span><span class="se">\x00</span><span class="s2">t</span><span class="se">\x00</span><span class="s2">r</span><span class="se">\x00</span><span class="s2">a</span><span class="se">\x00</span><span class="s2">g</span><span class="se">\x00</span><span class="s2"> </span><span class="se">\x00</span><span class="s2">i</span><span class="se">\x00</span><span class="s2">c</span><span class="se">\x00</span><span class="s2">h</span><span class="se">\x00</span><span class="s2"> </span><span class="se">\x00</span><span class="s2">d</span><span class="se">\x00</span><span class="s2">i</span><span class="se">\x00</span><span class="s2">c</span><span class="se">\x00</span><span class="s2">h</span><span class="se">\x00</span><span class="s2"> </span><span class="se">\x00</span><span class="s2">f</span><span class="se">\x00</span><span class="s2">o</span><span class="se">\x00</span><span class="s2">r</span><span class="se">\x00</span><span class="s2">t</span><span class="se">\x00</span><span class="s2">&quot;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">decoded</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="n">chardet</span><span class="o">.</span><span class="n">detect</span><span class="p">(</span><span class="n">x</span><span class="p">)[</span><span class="s1">&#39;encoding&#39;</span><span class="p">])</span>
<span class="gp">... </span>           <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="p">(</span><span class="n">text1</span><span class="p">,</span> <span class="n">text2</span><span class="p">,</span> <span class="n">text3</span><span class="p">)]</span>        <span class="c1"># doctest: +SKIP</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">v</span> <span class="o">=</span> <span class="n">CountVectorizer</span><span class="p">()</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">decoded</span><span class="p">)</span><span class="o">.</span><span class="n">vocabulary_</span>    <span class="c1"># doctest: +SKIP</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">term</span> <span class="ow">in</span> <span class="n">v</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>                           <span class="c1"># doctest: +SKIP</span>
</pre></div>
</div>
<p>(Depending on the version of <code class="docutils literal notranslate"><span class="pre">chardet</span></code>, it might get the first one wrong.)</p>
<p>For an introduction to Unicode and character encodings in general,
see Joel Spolsky’s <a class="reference external" href="https://www.joelonsoftware.com/articles/Unicode.html">Absolute Minimum Every Software Developer Must Know
About Unicode</a>.</p>
</div>
<div class="section" id="applications-and-examples">
<h3>6.2.3.6. Applications and examples<a class="headerlink" href="#applications-and-examples" title="Permalink to this headline">¶</a></h3>
<p>The bag of words representation is quite simplistic but surprisingly
useful in practice.</p>
<p>In particular in a <strong>supervised setting</strong> it can be successfully combined
with fast and scalable linear models to train <strong>document classifiers</strong>,
for instance:</p>
<blockquote>
<div><ul class="simple">
<li><p><a class="reference internal" href="../auto_examples/text/plot_document_classification_20newsgroups.html#sphx-glr-auto-examples-text-plot-document-classification-20newsgroups-py"><span class="std std-ref">Classification of text documents using sparse features</span></a></p></li>
</ul>
</div></blockquote>
<p>In an <strong>unsupervised setting</strong> it can be used to group similar documents
together by applying clustering algorithms such as <a class="reference internal" href="clustering.html#k-means"><span class="std std-ref">K-means</span></a>:</p>
<blockquote>
<div><ul class="simple">
<li><p><a class="reference internal" href="../auto_examples/text/plot_document_clustering.html#sphx-glr-auto-examples-text-plot-document-clustering-py"><span class="std std-ref">Clustering text documents using k-means</span></a></p></li>
</ul>
</div></blockquote>
<p>Finally it is possible to discover the main topics of a corpus by
relaxing the hard assignment constraint of clustering, for instance by
using <a class="reference internal" href="decomposition.html#nmf"><span class="std std-ref">Non-negative matrix factorization (NMF or NNMF)</span></a>:</p>
<blockquote>
<div><ul class="simple">
<li><p><a class="reference internal" href="../auto_examples/applications/plot_topics_extraction_with_nmf_lda.html#sphx-glr-auto-examples-applications-plot-topics-extraction-with-nmf-lda-py"><span class="std std-ref">Topic extraction with Non-negative Matrix Factorization and Latent Dirichlet Allocation</span></a></p></li>
</ul>
</div></blockquote>
</div>
<div class="section" id="limitations-of-the-bag-of-words-representation">
<h3>6.2.3.7. Limitations of the Bag of Words representation<a class="headerlink" href="#limitations-of-the-bag-of-words-representation" title="Permalink to this headline">¶</a></h3>
<p>A collection of unigrams (what bag of words is) cannot capture phrases
and multi-word expressions, effectively disregarding any word order
dependence. Additionally, the bag of words model doesn’t account for potential
misspellings or word derivations.</p>
<p>N-grams to the rescue! Instead of building a simple collection of
unigrams (n=1), one might prefer a collection of bigrams (n=2), where
occurrences of pairs of consecutive words are counted.</p>
<p>One might alternatively consider a collection of character n-grams, a
representation resilient against misspellings and derivations.</p>
<p>For example, let’s say we’re dealing with a corpus of two documents:
<code class="docutils literal notranslate"><span class="pre">['words',</span> <span class="pre">'wprds']</span></code>. The second document contains a misspelling
of the word ‘words’.
A simple bag of words representation would consider these two as
very distinct documents, differing in both of the two possible features.
A character 2-gram representation, however, would find the documents
matching in 4 out of 8 features, which may help the preferred classifier
decide better:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">ngram_vectorizer</span> <span class="o">=</span> <span class="n">CountVectorizer</span><span class="p">(</span><span class="n">analyzer</span><span class="o">=</span><span class="s1">&#39;char_wb&#39;</span><span class="p">,</span> <span class="n">ngram_range</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">counts</span> <span class="o">=</span> <span class="n">ngram_vectorizer</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">([</span><span class="s1">&#39;words&#39;</span><span class="p">,</span> <span class="s1">&#39;wprds&#39;</span><span class="p">])</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">ngram_vectorizer</span><span class="o">.</span><span class="n">get_feature_names</span><span class="p">()</span> <span class="o">==</span> <span class="p">(</span>
<span class="gp">... </span>    <span class="p">[</span><span class="s1">&#39; w&#39;</span><span class="p">,</span> <span class="s1">&#39;ds&#39;</span><span class="p">,</span> <span class="s1">&#39;or&#39;</span><span class="p">,</span> <span class="s1">&#39;pr&#39;</span><span class="p">,</span> <span class="s1">&#39;rd&#39;</span><span class="p">,</span> <span class="s1">&#39;s &#39;</span><span class="p">,</span> <span class="s1">&#39;wo&#39;</span><span class="p">,</span> <span class="s1">&#39;wp&#39;</span><span class="p">])</span>
<span class="go">True</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">counts</span><span class="o">.</span><span class="n">toarray</span><span class="p">()</span><span class="o">.</span><span class="n">astype</span><span class="p">(</span><span class="nb">int</span><span class="p">)</span>
<span class="go">array([[1, 1, 1, 0, 1, 1, 1, 0],</span>
<span class="go">       [1, 1, 0, 1, 1, 1, 0, 1]])</span>
</pre></div>
</div>
<p>In the above example, <code class="docutils literal notranslate"><span class="pre">char_wb</span></code> analyzer is used, which creates n-grams
only from characters inside word boundaries (padded with space on each
side). The <code class="docutils literal notranslate"><span class="pre">char</span></code> analyzer, alternatively, creates n-grams that
span across words:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">ngram_vectorizer</span> <span class="o">=</span> <span class="n">CountVectorizer</span><span class="p">(</span><span class="n">analyzer</span><span class="o">=</span><span class="s1">&#39;char_wb&#39;</span><span class="p">,</span> <span class="n">ngram_range</span><span class="o">=</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">ngram_vectorizer</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">([</span><span class="s1">&#39;jumpy fox&#39;</span><span class="p">])</span>
<span class="go">&lt;1x4 sparse matrix of type &#39;&lt;... &#39;numpy.int64&#39;&gt;&#39;</span>
<span class="go">   with 4 stored elements in Compressed Sparse ... format&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">ngram_vectorizer</span><span class="o">.</span><span class="n">get_feature_names</span><span class="p">()</span> <span class="o">==</span> <span class="p">(</span>
<span class="gp">... </span>    <span class="p">[</span><span class="s1">&#39; fox &#39;</span><span class="p">,</span> <span class="s1">&#39; jump&#39;</span><span class="p">,</span> <span class="s1">&#39;jumpy&#39;</span><span class="p">,</span> <span class="s1">&#39;umpy &#39;</span><span class="p">])</span>
<span class="go">True</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">ngram_vectorizer</span> <span class="o">=</span> <span class="n">CountVectorizer</span><span class="p">(</span><span class="n">analyzer</span><span class="o">=</span><span class="s1">&#39;char&#39;</span><span class="p">,</span> <span class="n">ngram_range</span><span class="o">=</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">ngram_vectorizer</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">([</span><span class="s1">&#39;jumpy fox&#39;</span><span class="p">])</span>
<span class="go">&lt;1x5 sparse matrix of type &#39;&lt;... &#39;numpy.int64&#39;&gt;&#39;</span>
<span class="go">    with 5 stored elements in Compressed Sparse ... format&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">ngram_vectorizer</span><span class="o">.</span><span class="n">get_feature_names</span><span class="p">()</span> <span class="o">==</span> <span class="p">(</span>
<span class="gp">... </span>    <span class="p">[</span><span class="s1">&#39;jumpy&#39;</span><span class="p">,</span> <span class="s1">&#39;mpy f&#39;</span><span class="p">,</span> <span class="s1">&#39;py fo&#39;</span><span class="p">,</span> <span class="s1">&#39;umpy &#39;</span><span class="p">,</span> <span class="s1">&#39;y fox&#39;</span><span class="p">])</span>
<span class="go">True</span>
</pre></div>
</div>
<p>The word boundaries-aware variant <code class="docutils literal notranslate"><span class="pre">char_wb</span></code> is especially interesting
for languages that use white-spaces for word separation as it generates
significantly less noisy features than the raw <code class="docutils literal notranslate"><span class="pre">char</span></code> variant in
that case. For such languages it can increase both the predictive
accuracy and convergence speed of classifiers trained using such
features while retaining the robustness with regards to misspellings and
word derivations.</p>
<p>While some local positioning information can be preserved by extracting
n-grams instead of individual words, bag of words and bag of n-grams
destroy most of the inner structure of the document and hence most of
the meaning carried by that internal structure.</p>
<p>In order to address the wider task of Natural Language Understanding,
the local structure of sentences and paragraphs should thus be taken
into account. Many such models will thus be casted as “Structured output”
problems which are currently outside of the scope of scikit-learn.</p>
</div>
<div class="section" id="vectorizing-a-large-text-corpus-with-the-hashing-trick">
<span id="hashing-vectorizer"></span><h3>6.2.3.8. Vectorizing a large text corpus with the hashing trick<a class="headerlink" href="#vectorizing-a-large-text-corpus-with-the-hashing-trick" title="Permalink to this headline">¶</a></h3>
<p>The above vectorization scheme is simple but the fact that it holds an <strong>in-
memory mapping from the string tokens to the integer feature indices</strong> (the
<code class="docutils literal notranslate"><span class="pre">vocabulary_</span></code> attribute) causes several <strong>problems when dealing with large
datasets</strong>:</p>
<ul class="simple">
<li><p>the larger the corpus, the larger the vocabulary will grow and hence the
memory use too,</p></li>
<li><p>fitting requires the allocation of intermediate data structures
of size proportional to that of the original dataset.</p></li>
<li><p>building the word-mapping requires a full pass over the dataset hence it is
not possible to fit text classifiers in a strictly online manner.</p></li>
<li><p>pickling and un-pickling vectorizers with a large <code class="docutils literal notranslate"><span class="pre">vocabulary_</span></code> can be very
slow (typically much slower than pickling / un-pickling flat data structures
such as a NumPy array of the same size),</p></li>
<li><p>it is not easily possible to split the vectorization work into concurrent sub
tasks as the <code class="docutils literal notranslate"><span class="pre">vocabulary_</span></code> attribute would have to be a shared state with a
fine grained synchronization barrier: the mapping from token string to
feature index is dependent on ordering of the first occurrence of each token
hence would have to be shared, potentially harming the concurrent workers’
performance to the point of making them slower than the sequential variant.</p></li>
</ul>
<p>It is possible to overcome those limitations by combining the “hashing trick”
(<a class="reference internal" href="#feature-hashing"><span class="std std-ref">Feature hashing</span></a>) implemented by the
<a class="reference internal" href="generated/sklearn.feature_extraction.FeatureHasher.html#sklearn.feature_extraction.FeatureHasher" title="sklearn.feature_extraction.FeatureHasher"><code class="xref py py-class docutils literal notranslate"><span class="pre">sklearn.feature_extraction.FeatureHasher</span></code></a> class and the text
preprocessing and tokenization features of the <a class="reference internal" href="generated/sklearn.feature_extraction.text.CountVectorizer.html#sklearn.feature_extraction.text.CountVectorizer" title="sklearn.feature_extraction.text.CountVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">CountVectorizer</span></code></a>.</p>
<p>This combination is implementing in <a class="reference internal" href="generated/sklearn.feature_extraction.text.HashingVectorizer.html#sklearn.feature_extraction.text.HashingVectorizer" title="sklearn.feature_extraction.text.HashingVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">HashingVectorizer</span></code></a>,
a transformer class that is mostly API compatible with <a class="reference internal" href="generated/sklearn.feature_extraction.text.CountVectorizer.html#sklearn.feature_extraction.text.CountVectorizer" title="sklearn.feature_extraction.text.CountVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">CountVectorizer</span></code></a>.
<a class="reference internal" href="generated/sklearn.feature_extraction.text.HashingVectorizer.html#sklearn.feature_extraction.text.HashingVectorizer" title="sklearn.feature_extraction.text.HashingVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">HashingVectorizer</span></code></a> is stateless,
meaning that you don’t have to call <code class="docutils literal notranslate"><span class="pre">fit</span></code> on it:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">sklearn.feature_extraction.text</span> <span class="kn">import</span> <span class="n">HashingVectorizer</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">hv</span> <span class="o">=</span> <span class="n">HashingVectorizer</span><span class="p">(</span><span class="n">n_features</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">hv</span><span class="o">.</span><span class="n">transform</span><span class="p">(</span><span class="n">corpus</span><span class="p">)</span>
<span class="go">&lt;4x10 sparse matrix of type &#39;&lt;... &#39;numpy.float64&#39;&gt;&#39;</span>
<span class="go">    with 16 stored elements in Compressed Sparse ... format&gt;</span>
</pre></div>
</div>
<p>You can see that 16 non-zero feature tokens were extracted in the vector
output: this is less than the 19 non-zeros extracted previously by the
<a class="reference internal" href="generated/sklearn.feature_extraction.text.CountVectorizer.html#sklearn.feature_extraction.text.CountVectorizer" title="sklearn.feature_extraction.text.CountVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">CountVectorizer</span></code></a> on the same toy corpus. The discrepancy comes from
hash function collisions because of the low value of the <code class="docutils literal notranslate"><span class="pre">n_features</span></code> parameter.</p>
<p>In a real world setting, the <code class="docutils literal notranslate"><span class="pre">n_features</span></code> parameter can be left to its
default value of <code class="docutils literal notranslate"><span class="pre">2</span> <span class="pre">**</span> <span class="pre">20</span></code> (roughly one million possible features). If memory
or downstream models size is an issue selecting a lower value such as <code class="docutils literal notranslate"><span class="pre">2</span> <span class="pre">**</span>
<span class="pre">18</span></code> might help without introducing too many additional collisions on typical
text classification tasks.</p>
<p>Note that the dimensionality does not affect the CPU training time of
algorithms which operate on CSR matrices (<code class="docutils literal notranslate"><span class="pre">LinearSVC(dual=True)</span></code>,
<code class="docutils literal notranslate"><span class="pre">Perceptron</span></code>, <code class="docutils literal notranslate"><span class="pre">SGDClassifier</span></code>, <code class="docutils literal notranslate"><span class="pre">PassiveAggressive</span></code>) but it does for
algorithms that work with CSC matrices (<code class="docutils literal notranslate"><span class="pre">LinearSVC(dual=False)</span></code>, <code class="docutils literal notranslate"><span class="pre">Lasso()</span></code>,
etc).</p>
<p>Let’s try again with the default setting:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">hv</span> <span class="o">=</span> <span class="n">HashingVectorizer</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">hv</span><span class="o">.</span><span class="n">transform</span><span class="p">(</span><span class="n">corpus</span><span class="p">)</span>
<span class="go">&lt;4x1048576 sparse matrix of type &#39;&lt;... &#39;numpy.float64&#39;&gt;&#39;</span>
<span class="go">    with 19 stored elements in Compressed Sparse ... format&gt;</span>
</pre></div>
</div>
<p>We no longer get the collisions, but this comes at the expense of a much larger
dimensionality of the output space.
Of course, other terms than the 19 used here
might still collide with each other.</p>
<p>The <a class="reference internal" href="generated/sklearn.feature_extraction.text.HashingVectorizer.html#sklearn.feature_extraction.text.HashingVectorizer" title="sklearn.feature_extraction.text.HashingVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">HashingVectorizer</span></code></a> also comes with the following limitations:</p>
<ul class="simple">
<li><p>it is not possible to invert the model (no <code class="docutils literal notranslate"><span class="pre">inverse_transform</span></code> method),
nor to access the original string representation of the features,
because of the one-way nature of the hash function that performs the mapping.</p></li>
<li><p>it does not provide IDF weighting as that would introduce statefulness in the
model. A <a class="reference internal" href="generated/sklearn.feature_extraction.text.TfidfTransformer.html#sklearn.feature_extraction.text.TfidfTransformer" title="sklearn.feature_extraction.text.TfidfTransformer"><code class="xref py py-class docutils literal notranslate"><span class="pre">TfidfTransformer</span></code></a> can be appended to it in a pipeline if
required.</p></li>
</ul>
</div>
<div class="section" id="performing-out-of-core-scaling-with-hashingvectorizer">
<h3>6.2.3.9. Performing out-of-core scaling with HashingVectorizer<a class="headerlink" href="#performing-out-of-core-scaling-with-hashingvectorizer" title="Permalink to this headline">¶</a></h3>
<p>An interesting development of using a <a class="reference internal" href="generated/sklearn.feature_extraction.text.HashingVectorizer.html#sklearn.feature_extraction.text.HashingVectorizer" title="sklearn.feature_extraction.text.HashingVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">HashingVectorizer</span></code></a> is the ability
to perform <a class="reference external" href="https://en.wikipedia.org/wiki/Out-of-core_algorithm">out-of-core</a> scaling. This means that we can learn from data that
does not fit into the computer’s main memory.</p>
<p>A strategy to implement out-of-core scaling is to stream data to the estimator
in mini-batches. Each mini-batch is vectorized using <a class="reference internal" href="generated/sklearn.feature_extraction.text.HashingVectorizer.html#sklearn.feature_extraction.text.HashingVectorizer" title="sklearn.feature_extraction.text.HashingVectorizer"><code class="xref py py-class docutils literal notranslate"><span class="pre">HashingVectorizer</span></code></a>
so as to guarantee that the input space of the estimator has always the same
dimensionality. The amount of memory used at any time is thus bounded by the
size of a mini-batch. Although there is no limit to the amount of data that can
be ingested using such an approach, from a practical point of view the learning
time is often limited by the CPU time one wants to spend on the task.</p>
<p>For a full-fledged example of out-of-core scaling in a text classification
task see <a class="reference internal" href="../auto_examples/applications/plot_out_of_core_classification.html#sphx-glr-auto-examples-applications-plot-out-of-core-classification-py"><span class="std std-ref">Out-of-core classification of text documents</span></a>.</p>
</div>
<div class="section" id="customizing-the-vectorizer-classes">
<h3>6.2.3.10. Customizing the vectorizer classes<a class="headerlink" href="#customizing-the-vectorizer-classes" title="Permalink to this headline">¶</a></h3>
<p>It is possible to customize the behavior by passing a callable
to the vectorizer constructor:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">my_tokenizer</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
<span class="gp">... </span>    <span class="k">return</span> <span class="n">s</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">vectorizer</span> <span class="o">=</span> <span class="n">CountVectorizer</span><span class="p">(</span><span class="n">tokenizer</span><span class="o">=</span><span class="n">my_tokenizer</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">vectorizer</span><span class="o">.</span><span class="n">build_analyzer</span><span class="p">()(</span><span class="sa">u</span><span class="s2">&quot;Some... punctuation!&quot;</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span>
<span class="gp">... </span>    <span class="p">[</span><span class="s1">&#39;some...&#39;</span><span class="p">,</span> <span class="s1">&#39;punctuation!&#39;</span><span class="p">])</span>
<span class="go">True</span>
</pre></div>
</div>
<p>In particular we name:</p>
<blockquote>
<div><ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">preprocessor</span></code>: a callable that takes an entire document as input (as a
single string), and returns a possibly transformed version of the document,
still as an entire string. This can be used to remove HTML tags, lowercase
the entire document, etc.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">tokenizer</span></code>: a callable that takes the output from the preprocessor
and splits it into tokens, then returns a list of these.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">analyzer</span></code>: a callable that replaces the preprocessor and tokenizer.
The default analyzers all call the preprocessor and tokenizer, but custom
analyzers will skip this. N-gram extraction and stop word filtering take
place at the analyzer level, so a custom analyzer may have to reproduce
these steps.</p></li>
</ul>
</div></blockquote>
<p>(Lucene users might recognize these names, but be aware that scikit-learn
concepts may not map one-to-one onto Lucene concepts.)</p>
<p>To make the preprocessor, tokenizer and analyzers aware of the model
parameters it is possible to derive from the class and override the
<code class="docutils literal notranslate"><span class="pre">build_preprocessor</span></code>, <code class="docutils literal notranslate"><span class="pre">build_tokenizer</span></code> and <code class="docutils literal notranslate"><span class="pre">build_analyzer</span></code>
factory methods instead of passing custom functions.</p>
<p>Some tips and tricks:</p>
<blockquote>
<div><ul>
<li><p>If documents are pre-tokenized by an external package, then store them in
files (or strings) with the tokens separated by whitespace and pass
<code class="docutils literal notranslate"><span class="pre">analyzer=str.split</span></code></p></li>
<li><p>Fancy token-level analysis such as stemming, lemmatizing, compound
splitting, filtering based on part-of-speech, etc. are not included in the
scikit-learn codebase, but can be added by customizing either the
tokenizer or the analyzer.
Here’s a <code class="docutils literal notranslate"><span class="pre">CountVectorizer</span></code> with a tokenizer and lemmatizer using
<a class="reference external" href="https://www.nltk.org/">NLTK</a>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">nltk</span> <span class="kn">import</span> <span class="n">word_tokenize</span>          
<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">nltk.stem</span> <span class="kn">import</span> <span class="n">WordNetLemmatizer</span> 
<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">LemmaTokenizer</span><span class="p">:</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="gp">... </span>        <span class="bp">self</span><span class="o">.</span><span class="n">wnl</span> <span class="o">=</span> <span class="n">WordNetLemmatizer</span><span class="p">()</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">doc</span><span class="p">):</span>
<span class="gp">... </span>        <span class="k">return</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">wnl</span><span class="o">.</span><span class="n">lemmatize</span><span class="p">(</span><span class="n">t</span><span class="p">)</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">word_tokenize</span><span class="p">(</span><span class="n">doc</span><span class="p">)]</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">vect</span> <span class="o">=</span> <span class="n">CountVectorizer</span><span class="p">(</span><span class="n">tokenizer</span><span class="o">=</span><span class="n">LemmaTokenizer</span><span class="p">())</span>  
</pre></div>
</div>
<p>(Note that this will not filter out punctuation.)</p>
<p>The following example will, for instance, transform some British spelling
to American spelling:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">re</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">to_british</span><span class="p">(</span><span class="n">tokens</span><span class="p">):</span>
<span class="gp">... </span>    <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">tokens</span><span class="p">:</span>
<span class="gp">... </span>        <span class="n">t</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;(...)our$&quot;</span><span class="p">,</span> <span class="sa">r</span><span class="s2">&quot;\1or&quot;</span><span class="p">,</span> <span class="n">t</span><span class="p">)</span>
<span class="gp">... </span>        <span class="n">t</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;([bt])re$&quot;</span><span class="p">,</span> <span class="sa">r</span><span class="s2">&quot;\1er&quot;</span><span class="p">,</span> <span class="n">t</span><span class="p">)</span>
<span class="gp">... </span>        <span class="n">t</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;([iy])s(e$|ing|ation)&quot;</span><span class="p">,</span> <span class="sa">r</span><span class="s2">&quot;\1z\2&quot;</span><span class="p">,</span> <span class="n">t</span><span class="p">)</span>
<span class="gp">... </span>        <span class="n">t</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;ogue$&quot;</span><span class="p">,</span> <span class="s2">&quot;og&quot;</span><span class="p">,</span> <span class="n">t</span><span class="p">)</span>
<span class="gp">... </span>        <span class="k">yield</span> <span class="n">t</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">CustomVectorizer</span><span class="p">(</span><span class="n">CountVectorizer</span><span class="p">):</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="nf">build_tokenizer</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="gp">... </span>        <span class="n">tokenize</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">build_tokenizer</span><span class="p">()</span>
<span class="gp">... </span>        <span class="k">return</span> <span class="k">lambda</span> <span class="n">doc</span><span class="p">:</span> <span class="nb">list</span><span class="p">(</span><span class="n">to_british</span><span class="p">(</span><span class="n">tokenize</span><span class="p">(</span><span class="n">doc</span><span class="p">)))</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">(</span><span class="n">CustomVectorizer</span><span class="p">()</span><span class="o">.</span><span class="n">build_analyzer</span><span class="p">()(</span><span class="sa">u</span><span class="s2">&quot;color colour&quot;</span><span class="p">))</span>
<span class="go">[...&#39;color&#39;, ...&#39;color&#39;]</span>
</pre></div>
</div>
<p>for other styles of preprocessing; examples include stemming, lemmatization,
or normalizing numerical tokens, with the latter illustrated in:</p>
<blockquote>
<div><ul class="simple">
<li><p><a class="reference internal" href="../auto_examples/bicluster/plot_bicluster_newsgroups.html#sphx-glr-auto-examples-bicluster-plot-bicluster-newsgroups-py"><span class="std std-ref">Biclustering documents with the Spectral Co-clustering algorithm</span></a></p></li>
</ul>
</div></blockquote>
</li>
</ul>
</div></blockquote>
<p>Customizing the vectorizer can also be useful when handling Asian languages
that do not use an explicit word separator such as whitespace.</p>
</div>
</div>
<div class="section" id="image-feature-extraction">
<span id="id6"></span><h2>6.2.4. Image feature extraction<a class="headerlink" href="#image-feature-extraction" title="Permalink to this headline">¶</a></h2>
<div class="section" id="patch-extraction">
<h3>6.2.4.1. Patch extraction<a class="headerlink" href="#patch-extraction" title="Permalink to this headline">¶</a></h3>
<p>The <a class="reference internal" href="generated/sklearn.feature_extraction.image.extract_patches_2d.html#sklearn.feature_extraction.image.extract_patches_2d" title="sklearn.feature_extraction.image.extract_patches_2d"><code class="xref py py-func docutils literal notranslate"><span class="pre">extract_patches_2d</span></code></a> function extracts patches from an image stored
as a two-dimensional array, or three-dimensional with color information along
the third axis. For rebuilding an image from all its patches, use
<a class="reference internal" href="generated/sklearn.feature_extraction.image.reconstruct_from_patches_2d.html#sklearn.feature_extraction.image.reconstruct_from_patches_2d" title="sklearn.feature_extraction.image.reconstruct_from_patches_2d"><code class="xref py py-func docutils literal notranslate"><span class="pre">reconstruct_from_patches_2d</span></code></a>. For example let use generate a 4x4 pixel
picture with 3 color channels (e.g. in RGB format):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">sklearn.feature_extraction</span> <span class="kn">import</span> <span class="n">image</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">one_image</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">4</span> <span class="o">*</span> <span class="mi">4</span> <span class="o">*</span> <span class="mi">3</span><span class="p">)</span><span class="o">.</span><span class="n">reshape</span><span class="p">((</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">one_image</span><span class="p">[:,</span> <span class="p">:,</span> <span class="mi">0</span><span class="p">]</span>  <span class="c1"># R channel of a fake RGB picture</span>
<span class="go">array([[ 0,  3,  6,  9],</span>
<span class="go">       [12, 15, 18, 21],</span>
<span class="go">       [24, 27, 30, 33],</span>
<span class="go">       [36, 39, 42, 45]])</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">patches</span> <span class="o">=</span> <span class="n">image</span><span class="o">.</span><span class="n">extract_patches_2d</span><span class="p">(</span><span class="n">one_image</span><span class="p">,</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="n">max_patches</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
<span class="gp">... </span>    <span class="n">random_state</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">patches</span><span class="o">.</span><span class="n">shape</span>
<span class="go">(2, 2, 2, 3)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">patches</span><span class="p">[:,</span> <span class="p">:,</span> <span class="p">:,</span> <span class="mi">0</span><span class="p">]</span>
<span class="go">array([[[ 0,  3],</span>
<span class="go">        [12, 15]],</span>

<span class="go">       [[15, 18],</span>
<span class="go">        [27, 30]]])</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">patches</span> <span class="o">=</span> <span class="n">image</span><span class="o">.</span><span class="n">extract_patches_2d</span><span class="p">(</span><span class="n">one_image</span><span class="p">,</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">patches</span><span class="o">.</span><span class="n">shape</span>
<span class="go">(9, 2, 2, 3)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">patches</span><span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="p">:,</span> <span class="p">:,</span> <span class="mi">0</span><span class="p">]</span>
<span class="go">array([[15, 18],</span>
<span class="go">       [27, 30]])</span>
</pre></div>
</div>
<p>Let us now try to reconstruct the original image from the patches by averaging
on overlapping areas:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">reconstructed</span> <span class="o">=</span> <span class="n">image</span><span class="o">.</span><span class="n">reconstruct_from_patches_2d</span><span class="p">(</span><span class="n">patches</span><span class="p">,</span> <span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">np</span><span class="o">.</span><span class="n">testing</span><span class="o">.</span><span class="n">assert_array_equal</span><span class="p">(</span><span class="n">one_image</span><span class="p">,</span> <span class="n">reconstructed</span><span class="p">)</span>
</pre></div>
</div>
<p>The <a class="reference internal" href="generated/sklearn.feature_extraction.image.PatchExtractor.html#sklearn.feature_extraction.image.PatchExtractor" title="sklearn.feature_extraction.image.PatchExtractor"><code class="xref py py-class docutils literal notranslate"><span class="pre">PatchExtractor</span></code></a> class works in the same way as
<a class="reference internal" href="generated/sklearn.feature_extraction.image.extract_patches_2d.html#sklearn.feature_extraction.image.extract_patches_2d" title="sklearn.feature_extraction.image.extract_patches_2d"><code class="xref py py-func docutils literal notranslate"><span class="pre">extract_patches_2d</span></code></a>, only it supports multiple images as input. It is
implemented as an estimator, so it can be used in pipelines. See:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">five_images</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">5</span> <span class="o">*</span> <span class="mi">4</span> <span class="o">*</span> <span class="mi">4</span> <span class="o">*</span> <span class="mi">3</span><span class="p">)</span><span class="o">.</span><span class="n">reshape</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">patches</span> <span class="o">=</span> <span class="n">image</span><span class="o">.</span><span class="n">PatchExtractor</span><span class="p">((</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span><span class="o">.</span><span class="n">transform</span><span class="p">(</span><span class="n">five_images</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">patches</span><span class="o">.</span><span class="n">shape</span>
<span class="go">(45, 2, 2, 3)</span>
</pre></div>
</div>
</div>
<div class="section" id="connectivity-graph-of-an-image">
<h3>6.2.4.2. Connectivity graph of an image<a class="headerlink" href="#connectivity-graph-of-an-image" title="Permalink to this headline">¶</a></h3>
<p>Several estimators in the scikit-learn can use connectivity information between
features or samples. For instance Ward clustering
(<a class="reference internal" href="clustering.html#hierarchical-clustering"><span class="std std-ref">Hierarchical clustering</span></a>) can cluster together only neighboring pixels
of an image, thus forming contiguous patches:</p>
<div class="figure align-center">
<a class="reference external image-reference" href="../auto_examples/cluster/plot_coin_ward_segmentation.html"><img alt="modules/../auto_examples/cluster/images/sphx_glr_plot_coin_ward_segmentation_001.png" src="modules/../auto_examples/cluster/images/sphx_glr_plot_coin_ward_segmentation_001.png" /></a>
</div>
<p>For this purpose, the estimators use a ‘connectivity’ matrix, giving
which samples are connected.</p>
<p>The function <a class="reference internal" href="generated/sklearn.feature_extraction.image.img_to_graph.html#sklearn.feature_extraction.image.img_to_graph" title="sklearn.feature_extraction.image.img_to_graph"><code class="xref py py-func docutils literal notranslate"><span class="pre">img_to_graph</span></code></a> returns such a matrix from a 2D or 3D
image. Similarly, <a class="reference internal" href="generated/sklearn.feature_extraction.image.grid_to_graph.html#sklearn.feature_extraction.image.grid_to_graph" title="sklearn.feature_extraction.image.grid_to_graph"><code class="xref py py-func docutils literal notranslate"><span class="pre">grid_to_graph</span></code></a> build a connectivity matrix for
images given the shape of these image.</p>
<p>These matrices can be used to impose connectivity in estimators that use
connectivity information, such as Ward clustering
(<a class="reference internal" href="clustering.html#hierarchical-clustering"><span class="std std-ref">Hierarchical clustering</span></a>), but also to build precomputed kernels,
or similarity matrices.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p><strong>Examples</strong></p>
<ul class="simple">
<li><p><a class="reference internal" href="../auto_examples/cluster/plot_coin_ward_segmentation.html#sphx-glr-auto-examples-cluster-plot-coin-ward-segmentation-py"><span class="std std-ref">A demo of structured Ward hierarchical clustering on an image of coins</span></a></p></li>
<li><p><a class="reference internal" href="../auto_examples/cluster/plot_segmentation_toy.html#sphx-glr-auto-examples-cluster-plot-segmentation-toy-py"><span class="std std-ref">Spectral clustering for image segmentation</span></a></p></li>
<li><p><a class="reference internal" href="../auto_examples/cluster/plot_feature_agglomeration_vs_univariate_selection.html#sphx-glr-auto-examples-cluster-plot-feature-agglomeration-vs-univariate-selection-py"><span class="std std-ref">Feature agglomeration vs. univariate selection</span></a></p></li>
</ul>
</div>
</div>
</div>
</div>


      </div>
    <div class="container">
      <footer class="sk-content-footer">
            &copy; 2007 - 2019, scikit-learn developers (BSD License).
          <a href="../_sources/modules/feature_extraction.rst.txt" rel="nofollow">Show this page source</a>
      </footer>
    </div>
  </div>
</div>
<script src="../_static/js/vendor/bootstrap.min.js"></script>

<script>
    window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
    ga('create', 'UA-22606712-2', 'auto');
    ga('set', 'anonymizeIp', true);
    ga('send', 'pageview');
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>


<script>
$(document).ready(function() {
    /* Add a [>>>] button on the top-right corner of code samples to hide
     * the >>> and ... prompts and the output and thus make the code
     * copyable. */
    var div = $('.highlight-python .highlight,' +
                '.highlight-python3 .highlight,' +
                '.highlight-pycon .highlight,' +
		'.highlight-default .highlight')
    var pre = div.find('pre');

    // get the styles from the current theme
    pre.parent().parent().css('position', 'relative');
    var hide_text = 'Hide prompts and outputs';
    var show_text = 'Show prompts and outputs';

    // create and add the button to all the code blocks that contain >>>
    div.each(function(index) {
        var jthis = $(this);
        if (jthis.find('.gp').length > 0) {
            var button = $('<span class="copybutton">&gt;&gt;&gt;</span>');
            button.attr('title', hide_text);
            button.data('hidden', 'false');
            jthis.prepend(button);
        }
        // tracebacks (.gt) contain bare text elements that need to be
        // wrapped in a span to work with .nextUntil() (see later)
        jthis.find('pre:has(.gt)').contents().filter(function() {
            return ((this.nodeType == 3) && (this.data.trim().length > 0));
        }).wrap('<span>');
    });

    // define the behavior of the button when it's clicked
    $('.copybutton').click(function(e){
        e.preventDefault();
        var button = $(this);
        if (button.data('hidden') === 'false') {
            // hide the code output
            button.parent().find('.go, .gp, .gt').hide();
            button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'hidden');
            button.css('text-decoration', 'line-through');
            button.attr('title', show_text);
            button.data('hidden', 'true');
        } else {
            // show the code output
            button.parent().find('.go, .gp, .gt').show();
            button.next('pre').find('.gt').nextUntil('.gp, .go').css('visibility', 'visible');
            button.css('text-decoration', 'none');
            button.attr('title', hide_text);
            button.data('hidden', 'false');
        }
    });

	/*** Add permalink buttons next to glossary terms ***/
	$('dl.glossary > dt[id]').append(function() {
		return ('<a class="headerlink" href="#' +
			    this.getAttribute('id') +
			    '" title="Permalink to this term">¶</a>');
	});
  /*** Hide navbar when scrolling down ***/
  // Returns true when headerlink target matches hash in url
  (function() {
    hashTargetOnTop = function() {
        var hash = window.location.hash;
        if ( hash.length < 2 ) { return false; }

        var target = document.getElementById( hash.slice(1) );
        if ( target === null ) { return false; }

        var top = target.getBoundingClientRect().top;
        return (top < 2) && (top > -2);
    };

    // Hide navbar on load if hash target is on top
    var navBar = document.getElementById("navbar");
    var navBarToggler = document.getElementById("sk-navbar-toggler");
    var navBarHeightHidden = "-" + navBar.getBoundingClientRect().height + "px";
    var $window = $(window);

    hideNavBar = function() {
        navBar.style.top = navBarHeightHidden;
    };

    showNavBar = function() {
        navBar.style.top = "0";
    }

    if (hashTargetOnTop()) {
        hideNavBar()
    }

    var prevScrollpos = window.pageYOffset;
    hideOnScroll = function(lastScrollTop) {
        if (($window.width() < 768) && (navBarToggler.getAttribute("aria-expanded") === 'true')) {
            return;
        }
        if (lastScrollTop > 2 && (prevScrollpos <= lastScrollTop) || hashTargetOnTop()){
            hideNavBar()
        } else {
            showNavBar()
        }
        prevScrollpos = lastScrollTop;
    };

    /*** high preformance scroll event listener***/
    var raf = window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        window.oRequestAnimationFrame;
    var lastScrollTop = $window.scrollTop();

    if (raf) {
        loop();
    }

    function loop() {
        var scrollTop = $window.scrollTop();
        if (lastScrollTop === scrollTop) {
            raf(loop);
            return;
        } else {
            lastScrollTop = scrollTop;
            hideOnScroll(lastScrollTop);
            raf(loop);
        }
    }
  })();
});

</script>
    
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
    
</body>
</html>